package com.atguigu.gmall.gateway.filter;

import com.atguigu.gmall.common.utils.IpUtils;
import com.atguigu.gmall.common.utils.JwtUtils;
import com.atguigu.gmall.common.utils.RsaUtils;
import com.atguigu.gmall.gateway.config.JwtProperties;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Component
@EnableConfigurationProperties(JwtProperties.class)
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.KeyValueConfig> {

    @Autowired
    JwtProperties jwtProperties;
    public AuthGatewayFilterFactory(){
        super(KeyValueConfig.class);
    }
    public List<String> shortcutFieldOrder() {

        return Arrays.asList("keys");
    }

    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST;
    }

    //实现抽象类中的抽象方法即可实现定点过滤


    @Override
    public GatewayFilter apply(KeyValueConfig keyValueConfig) {


        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //1.判断路径是否在拦截名单内
                ServerHttpRequest request = exchange.getRequest();
                ServerHttpResponse response = exchange.getResponse();
                //当前请求的路径
                String curpath = request.getURI().getPath();
                List<String> keys = keyValueConfig.keys;
                //判断拦截条件（1、keys为空，或者，keys中的数据与curpath中的数据匹配时拦截）,取反，路径不为空，并且当前路径不以拦截名单中的所有路径开头
                if (!CollectionUtils.isEmpty(keys)&& keys.stream().allMatch(key->curpath.startsWith(key))){
                return chain.filter(exchange);//直接放行
                }
            //反之说明匹配上了，获取cookie中的token
                String token = request.getHeaders().getFirst("token");//异步请求放在头信息里
                if (StringUtils.isEmpty(token)){
                    //如果从请求中的头信息中没有获取到，则尝试从cookie中获取
                    MultiValueMap<String, HttpCookie> cookies = request.getCookies();
                    if(cookies!=null&&cookies.containsKey(jwtProperties.getCookieName())){
                        token = cookies.getFirst(jwtProperties.getCookieName()).getValue();
                    }
                }
                //判断token是否为空 ，如果为空则跳转值登录页面
                if(StringUtils.isEmpty(token)){
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://sso.gmall.com/toLogin.html?returnUrl="+request.getURI());
                    return response.setComplete();
                }

                //token不为空，则对token中的数据进行校验
                try {
                    Map<String, Object> tokenMap = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey());
                    String ip = tokenMap.get("ip").toString();
                    String ipAddressAtGateway = IpUtils.getIpAddressAtGateway(request);
                    if (!StringUtils.equals(ip,ipAddressAtGateway)){
                        response.setStatusCode(HttpStatus.SEE_OTHER);
                        response.getHeaders().set(HttpHeaders.LOCATION,"http://sso.gmall.com/tologin.html?returnUrl="+request.getURI());
                        return response.setComplete();
                    }
                    //两者的ip地址相同则将载荷中的数据发送到后续的微服务
                    String username = tokenMap.get("username").toString();
                    request.mutate().header("userId", tokenMap.get("id").toString()).header("username", username).build();
                    exchange.mutate().request(request).build();


                } catch (Exception e) {
                    e.printStackTrace();
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://sso.gmall.com/tologin.html?returnUrl="+request.getURI());
                    return response.setComplete();
                }


                return chain.filter(exchange);

            }
        };
    }
    @Data
    public static class KeyValueConfig{
        List<String> keys;
    }

}
